<template>
    <slot v-if="showHeader" name="header">
        <div class="select-tree-filter-div">
            <el-button class="global-btn-second" @click="onRefreshTree">
                <i class="ri-refresh-line"></i>
                <span>{{ $t('刷新') }}</span>
            </el-button>

            <input autocomplete="new-password" hidden type="password" />
            <el-input
                v-model="apiSearchKey"
                :placeholder="$t('请搜索')"
                autocomplete
                name="select-tree-search"
                type="search"
                @input="onSearchChange"
            >
                <template #prefix>
                    <i class="ri-search-line"></i>
                </template>
            </el-input>
        </div>
    </slot>

    <y9Tree
        ref="y9TreeRef"
        :checkStrictly="checkStrictly"
        :data="alreadyLoadTreeData"
        :highlightCurrent="highlightCurrent"
        :lazy="lazy"
        :load="onTreeLazyLoad"
        showCheckbox
        @node-click="onNodeClick"
        @node-expand="onNodeExpand"
        @check-change="onCheckChange"
    >
        <template #title="{ item }">
            <i :class="item.title_icon"></i>
            <span>{{ item[nodeLabel] }}</span>
        </template>
        <!-- 	<template #actions="{item}" >
                <i v-if="item.delete_icon" class="ri-delete-bin-7-line" @click="onRemoveNode(item)"></i>
            </template> -->
    </y9Tree>
</template>

<script lang="ts" setup>
    import { $dataType } from '@/utils/object'; //工具类
    import { ref, watch } from 'vue';
    // 注入 字体对象

    const props = defineProps({
        treeApiObj: {
            //tree接口对象,参数名称请严格按照以下注释进行传参。
            /**
         {
         topLevel:treeInterface,//可以直接返回接口，也可以返回一个函数，函数里返回tree数据。
         childLevel:{//子级（二级及二级以上）tree接口
         api:getTreeItemById,//可以直接返回接口，也可以返回一个函数，函数里返回tree数据，如果返回函数，params就不需要传入。
         params:{}//请求参数，注意使用此组件，parentId字段不需要传
         },
         search: {//搜索接口及参数
         api:getTreeItemById,
         params:{}/请求参数，注意使用此组件，key字段不需要传
         }
         }
         */
            type: Object
        },

        selectField: {
            //设置需要选择的字段
            type: Array
        },

        showHeader: {
            //是否显示头部
            type: Boolean,
            default: true
        },
        nodeLabel: {
            //显示的节点属性
            type: String,
            default: 'name'
        },

        checkStrictly: {
            //是否严格的遵循父子不互相关联的做法，默认为 false,父子互相关联
            type: Boolean,
            default: true
        },

        highlightCurrent: {
            //是否高亮当前选中节点
            type: Boolean,
            default: false
        }
    });

    //已经加载的tree数据
    const alreadyLoadTreeData = ref([]);

    const emits = defineEmits(['onTreeClick', 'update:onCheckBox', 'change', 'onCheckChange', 'onNodeExpand']);

    //点击节点
    const onNodeClick = (node) => {
        emits('onTreeClick', node);
    };

    //节点被展开时触发的事件
    const onNodeExpand = (node) => {
        emits('onNodeExpand', node);
    };

    //当复选框被点击的时候触发
    const onCheckChange = (node, isChecked, childIsHaveChecked) => {
        emits('onCheckChange', node, isChecked, childIsHaveChecked);
    };

    //tree实例
    const y9TreeRef = ref();

    //格式化懒加载的数据
    function formatLazyTreeData(data, isTopLevel?) {
        for (let i = 0; i < data.length; i++) {
            const item = data[i];

            if (props.selectField && props.selectField.length > 0) {
                //根据需要选择框的字段进行格式化
                const disabled: boolean = props.selectField.every((item2) => {
                    //every()方法会遍历数组的每一项,如果有一项不满足条件,则返回false,剩余的项将不会再执行检测。如果遍历完数组后,每一项都符合条,则返回true。
                    if ($dataType(item2.value) == 'array') {
                        return item2.value.includes(item[item2.fieldName]);
                    } else {
                        return item[item2.fieldName] == item2.value;
                    }
                });

                if (!item.disabled) {
                    item.disabled = !disabled; //设置不可以选中的字段禁止选择
                }
            }

            switch (item.orgType) {
                case 'Organization': //组织
                    item.title_icon = 'ri-stackshare-line';
                    break;

                case 'App':
                    item.title_icon = 'ri-stackshare-line';
                    break;

                case 'Department': //部门
                    item.title_icon = 'ri-slack-line';
                    break;

                case 'Group': //组
                    item.title_icon = 'ri-shield-star-line';
                    break;

                case 'Position': //岗位
                    item.title_icon = 'ri-shield-user-line';
                    item.isLeaf = true; //叶子节点（即没有展开按钮）
                    break;

                case 'Person': //人员
                    item.isLeaf = true; //叶子节点（即没有展开按钮）
                    item.title_icon = 'ri-women-line';
                    if (item.sex == 1) {
                        item.title_icon = 'ri-men-line';
                    }
                    if (item.disabled) {
                        item.name = item.name + (item.disabledRemark ? item.disabledRemark : '[禁用]');
                    }
                    break;

                default:
                    item.title_icon = '';
            }
            // 角色
            switch (item.orgType) {
                case 'role': //角色 人员
                    item.title_icon = 'ri-contacts-line';
                    item.isLeaf = true; //叶子节点（即没有展开按钮）
                    break;
                case 'folder': // 文件夹
                    item.title_icon = 'ri-folder-2-line';
                    break;
            }

            // 动态角色
            switch (item.orgType) {
                case 'dynamicRole': //
                    item.title_icon = 'ri-group-line';
                    item.isLeaf = true; //叶子节点（即没有展开按钮）
                    break;
            }
        }
    }

    //懒加载
    const onTreeLazyLoad = async (node, resolve: () => void) => {
        if (node.$level === 0) {
            //1.获取数据
            let data = [];
            const res = await props.treeApiObj?.topLevel(); //请求一级节点接口
            data = res.data || res;

            //2.格式化数据
            await formatLazyTreeData(data, true);

            //初始化数据后，默认选中第一个节点、设置第一个节点展开，模拟点击第一个节点
            const callBack = () => {
                if (data.length > 0) {
                    y9TreeRef.value.setExpandKeys([data[0].id]); //设置第一个节点展开
                }
            };
            return resolve(data, callBack); //返回一级节点数据
        } else {
            //1.获取数据
            let data = [];
            if (node.children && node.children.length > 0) {
                //如果有传入的数据就取传入的数据
                data = node.children;
            } else {
                //如果没有则取接口数据
                //整合参数
                let params = {};
                const childLevelParams = props.treeApiObj?.childLevel?.params;
                if (childLevelParams) {
                    params = childLevelParams;
                }
                params.parentId = node.id;
                //请求接口
                const res = await props.treeApiObj?.childLevel?.api(params);
                data = res.data || res;
            }

            //2.格式化数据
            await formatLazyTreeData(data, false);

            return resolve(data); //返回二级三级...节点数据
        }
    };

    //搜索关键字
    const apiSearchKey = ref('');

    let timer;
    const onSearchChange = (searchKey) => {
        clearTimeout(timer); //清空计时器
        timer = setTimeout(() => {
            postSearchApi(searchKey);
        }, 500);
    };

    watch(
        () => props.treeApiObj?.search?.params?.key,
        (searchKey) => {
            postSearchApi(searchKey);
        }
    );

    //请求搜索api
    async function postSearchApi(searchkey) {
        if (searchkey) {
            //有值就请求搜索api
            //整合参数
            let params = {};
            const searchParams = props.treeApiObj?.search?.params;
            if (searchParams) {
                params = searchParams;
            }
            params.key = searchkey;

            //请求搜索接口
            const res = await props.treeApiObj?.search?.api(params);
            const data = res.data;
            //格式化tree数据
            await formatLazyTreeData(data);
            // resourceType 为0 的parentId 为空
            await data?.map((item) => {
                if (item.resourceType == 0) {
                    item.parentId = '';
                }
            });
            //根据搜索结果转换成tree结构显示出来
            alreadyLoadTreeData.value = transformTreeBySearchResult(data);

            nextTick(() => {
                y9TreeRef.value.setExpandAll();
            });
        } else {
            //没有就获取获取已经懒加载过的数据，并且设置默认选中第一个节点、默认展开第一个节点，模拟点击第一个节点

            alreadyLoadTreeData.value = y9TreeRef.value.getLazyTreeData(); //获取已经懒加载过的数据

            nextTick(() => {
                if (alreadyLoadTreeData.value.length > 0) {
                    y9TreeRef.value.setCurrentKey(alreadyLoadTreeData.value[0].id); //设置第一个节点为高亮节点

                    y9TreeRef.value.setExpandKeys([alreadyLoadTreeData.value[0].id]); //设置第一个节点展开

                    onNodeClick(alreadyLoadTreeData.value[0]); //模拟点击第一个节点
                }
            });
        }
    }

    //根据搜索结果转换成tree结构
    function transformTreeBySearchResult(result) {
        const treeData = [];
        for (let i = 0; i < result.length; i++) {
            const item = result[i];
            if (!item.parentId) {
                //一级节点
                let node = item;

                const child = result.filter((resultItem) => resultItem.parentId === item.id);
                if (child.length > 0) {
                    //如果有子节点则递归子节点，进行组合
                    item.children = child;
                    const fn2 = (data) => {
                        for (let j = 0; j < data.length; j++) {
                            const itemJ = data[j];
                            const childs = result.filter((resultItem) => resultItem.parentId === itemJ.id);
                            if (childs.length > 0) {
                                itemJ.children = childs;
                                if (itemJ.children.length > 0) {
                                    fn2(itemJ.children);
                                }
                            }
                        }
                    };
                    fn2(item.children); //递归子节点
                }

                treeData.push(item);
            }
        }

        return treeData;
    }

    //是否懒加载
    const lazy: boolean = ref(true);

    //刷新tree
    const onRefreshTree = () => {
        alreadyLoadTreeData.value = [];
        lazy.value = false;
        setTimeout(() => {
            lazy.value = true;
        }, 0);
    };

    /**根据id查找tree节点信息
     * @param {Object} data 树的数据
     * @param {Object} targetId 目标节点id
     */
    function findNode(data, targetId) {
        let currNodeInfo = null;
        const fun = (data, targetId) => {
            for (let i = 0; i < data.length; i++) {
                const item = data[i];
                if (item.id === targetId) {
                    currNodeInfo = item;
                    break;
                }
                if (item.children && item.children.length > 0) {
                    fun(item.children, targetId);
                }
            }
        };
        fun(data, targetId);
        return currNodeInfo;
    }

    //设置树数据
    async function setTreeData(data) {
        await formatLazyTreeData(data);
        alreadyLoadTreeData.value = data;
    }

    //获取树数据
    function getTreeData() {
        return alreadyLoadTreeData.value;
    }

    defineExpose({
        y9TreeRef,
        onRefreshTree, //刷新tree
        getTreeData
    });
</script>

<style lang="scss" scoped>
    @import '@/theme/global.scss';
    @import '@/theme/global-vars.scss';
    @import '@/theme/global.scss';

    //过滤样式
    .select-tree-filter-div {
        display: flex;
        align-items: center;
        flex-wrap: wrap;
        margin-bottom: 16px;

        .el-button {
            margin-right: 16px;
            margin-bottom: 10px;
        }

        :deep(.el-input) {
            width: 250px;
            max-width: 100%;
            margin-bottom: 10px;

            .el-input__wrapper {
                border-radius: 30px;
                box-shadow: 0 2px 4px 0 rgb(0 0 0 / 5%);
                border: 1px solid var(--el-color-primary-light-7);
            }
        }
    }

    :deep(.node-title) {
        display: inline-flex;
        align-items: center;

        i {
            margin-right: 5px;
            font-weight: normal;
        }
    }

    :deep(.active-node) {
        .y9-tree-item-content {
            .y9-tree-item-content-div {
                .action-icons {
                    i {
                        color: var(--el-color-white) !important;
                    }
                }
            }
        }
    }
</style>
